//
// 请你设计并实现一个满足 
// LRU (最近最少使用) 缓存 约束的数据结构。
// 
//
// 
// 实现 
// LRUCache 类：
// 
//
// 
// 
// 
// LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 
// int get(int key) 如果关键字 key 存在于缓存中，则返回关键字的值，否则返回 -1 。 
// void put(int key, int value) 如果关键字 key 已经存在，则变更其数据值 value ；如果不存在，则向缓存中插入该组 
//key-value 。如果插入操作导致关键字数量超过 capacity ，则应该 逐出 最久未使用的关键字。 
// 
// 
// 
//
// 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。 
//
// 
//
// 示例： 
//
// 
//输入
//["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
//[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
//输出
//[null, null, null, 1, null, -1, null, -1, 3, 4]
//
//解释
//LRUCache lRUCache = new LRUCache(2);
//lRUCache.put(1, 1); // 缓存是 {1=1}
//lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
//lRUCache.get(1);    // 返回 1
//lRUCache.put(3, 3); // 该操作会使得关键字 2 作废，缓存是 {1=1, 3=3}
//lRUCache.get(2);    // 返回 -1 (未找到)
//lRUCache.put(4, 4); // 该操作会使得关键字 1 作废，缓存是 {4=4, 3=3}
//lRUCache.get(1);    // 返回 -1 (未找到)
//lRUCache.get(3);    // 返回 3
//lRUCache.get(4);    // 返回 4
// 
//
// 
//
// 提示： 
//
// 
// 1 <= capacity <= 3000 
// 0 <= key <= 10000 
// 0 <= value <= 10⁵ 
// 最多调用 2 * 10⁵ 次 get 和 put 
// 
//
// Related Topics 设计 哈希表 链表 双向链表 👍 2806 👎 0


package LeetCode.editor.cn;

import java.util.*;

/**
 * @author ldltd
 * @date 2023-08-16 12:26:32
 * @description 146.LRU 缓存
 */
public class LruCache {
    public static void main(String[] args) {
        //测试代码

    }

    //力扣代码
//leetcode submit region begin(Prohibit modification and deletion)
    /*不知道为什么慢*/
    class LRUCache {
        private int capity;
        private HashMap<Integer, Integer> map;
        private List<Integer> q;

        public LRUCache(int capacity) {
            this.capity = capacity;
            this.q = new LinkedList<>();
            this.map = new HashMap<Integer, Integer>();
        }

        public int get(int key) {
            if (map.containsKey(key)) {
                q.remove(((Integer) key));
                q.add(key);
                return map.get(key).intValue();
            } else {
                return -1;
            }
        }

        public void put(int key, int value) {
            if (!map.containsKey(key)) {
                //容量没满
                if (q.size() < capity) {
                    q.add(key);
                    map.put(key, value);
                    //满了
                } else {
                    Object o = q.get(0);
                    q.remove(o);
                    q.add(key);
                    map.remove(o);
                    map.put(key, value);
                }
                //包含则更新
            } else {
                q.remove((Integer) key);
                q.add(key);
                map.put(key, value);
            }
        }
    }

    /*用自带的linkedhashmap*/
    class LRUCache1 extends LinkedHashMap<Integer, Integer> {
        private int capacity;

        //loadfactor  负载因子当实际容量为额定容量的百分之时进行扩容，防止hash冲突，0.75可以较好的达到空间时间平衡
        public LRUCache1(int capacity) {
            super(capacity, 0.75F, true);
            this.capacity = capacity;
        }

        public int get(int key) {
            return super.getOrDefault(key, -1);
        }

        public void put(int key, int value) {
            super.put(key, value);
        }

        //linkedhashmap,默认的方法为空
        @Override
        protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
            return size() > capacity;
        }
    }

    class LRUCache2 {
        //双向链表
        class LinkedNode {
            int key;
            int value;
            LinkedNode pre;
            LinkedNode next;
            public LinkedNode() {}
            public LinkedNode(int _key, int _value) {
                key = _key;
                value = _value;
            }
        }
        private Map<Integer,LinkedNode> cache=new HashMap<Integer,LinkedNode>();
        private int size;
        private int capacity;
        private LinkedNode head,tail;
        public LRUCache2(int capacity){
            this.size=0;
            this.capacity=capacity;
            //伪头结点尾部节点
            head=new LinkedNode();
            tail=new LinkedNode();
            head.next=tail;
            tail.pre=head;
        }
        public int get(int key) {
            LinkedNode node = cache.get(key);
            if(node==null){
                return -1;
            }
            //如果Key存在，要移动到头部
            moveToHead(node);
            return node.value;
        }
        public void put(int key, int value) {
            LinkedNode node = cache.get(key);
            if(node==null){
                //key不存在，新建一个节点
                LinkedNode newNode = new LinkedNode(key, value);
                //加入hash表
                cache.put(key,newNode);
                //加入链表头部
                addToHead(newNode);
                ++size;
                if(size>capacity){
                    //超过容量，删除链表尾节点
                    LinkedNode tail = removeTail();
                    //删除hash中的
                    cache.remove(tail.key);
                    --size;
                }
            }else {
                //如果key存在，先从hash找，然后修改value，并移到头部
                node.value=value;
                moveToHead(node);
            }
        }
        private void moveToHead(LinkedNode node){
            remove(node);
            addToHead(node);
        }
        private void addToHead(LinkedNode node){
            node.pre=head;
            node.next=head.next;
            head.next.pre=node;
            head.next=node;
        }
        private void remove(LinkedNode node){
            node.pre.next=node.next;
            node.next.pre=node.pre;
        }
        private LinkedNode removeTail(){
            LinkedNode res = tail.pre;
            remove(res);
            return res;

        }



    }


/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */
//leetcode submit region end(Prohibit modification and deletion)

}
